<template>
  <div class="chatWindowAi">
    <c-title :hide="false" text="Ai客服"></c-title>
    <loading :show="sendStatus || audioStatus"></loading>
    <van-pull-refresh v-model="isLoading" @refresh="onRefresh">
      <div class="chat-scroll" id="chat-data" @click="opetFlag = false" :style="{ paddingBottom: opetFlag == true ? '17rem' : '3rem' }" ref="chatList">
        <div class="conversation" v-for="(item, index) in chatList" :key="index">
          <!-- item.direction_type === 0 是用户 1是客服  -->
          <div class="chat-msg my-msg" v-if="item.direction_type === 0">
            <div class="avater">
              <van-image :src="memberInfo.avatar" width="37px" height="37px" round fit="cover"></van-image>
            </div>
            <div class="content">
              <div class="my-info">
                <div class="txt">
                  <div class="txt-content">{{ item.content }}</div>
                </div>
                <div class="arrow-r"></div>
              </div>
            </div>
          </div>
          <div class="chat-msg other-msg" v-else>
            <div class="avater">
              <van-image :src="ai_avatar" width="37px" height="37px" round fit="cover" />
            </div>
            <div class="content">
              <div class="other-info">
                <div class="txt">
                  <div class="txt-content">
                    <audio-icon @closeLoad="closeLoad" @chatLoaded="scrollToBottom" @showLoad="showLoad" @childAudio="tap_Audio" :itemDatas="item" :open="xf_open"></audio-icon>
                  </div>
                </div>
                <div class="arrow-l"></div>
              </div>
            </div>
          </div>
        </div>
        <div v-if="show_tool_bar == 1" style="height: 2.75rem;"></div>
      </div>
    </van-pull-refresh>
    <template>
      <div class="chat-footer" style="height: auto" :class="[fun.getPhoneEnv() == 3 ? 'pcStyle' : '']">
        <div class="show_tool_bar" v-if="show_tool_bar == 1 && chat_tool_bars.length > 0">
          <div class="chat_tool_bars">
            <div class="chat_tool_item" v-for="item in chat_tool_bars" :key="item.id" @click="handClickChatToolBars(item)">{{ item.name }}</div>
          </div>
        </div>
        <div class="chat-opt-input" style="height: auto">
          <div class="chat-opt-input-box" style="width: 100%;align-items: end; padding: 0.5rem 0;">
            <van-field
              v-model="msgText"
              rows="1"
              :autosize="{ maxHeight: 100, minHeight: 20 }"
              type="textarea"
              :disabled="sendStatus"
              @focus="textInputFocus"
              style="margin-left: 0.5rem;padding: 6px 8px; border-radius: 0.5rem;line-height: 18px;"
              ref="inputEl"
            />
            <a class="chat-opt-send-msg-btn" style="flex-shrink: 0;margin-right: 0.5rem;" :class="{ 'disabled-send': sendStatus }" @click="sendMsg">发送</a>
          </div>
        </div>
      </div>
    </template>
  </div>
</template>
<script>
import { PullRefresh as VanPullRefresh, Image as VanImage } from "vant";
import loading from "components/loading";
import audioIcon from "./components/audioIcon";
export default {
  data() {
    return {
      chatList: [],
      memberInfo: {},
      messageId: "",
      // 发送状态
      sendStatus: false,
      msgText: "",
      ai_avatar: "",
      xf_open: false,
      audioChild: null, //音频播放对象
      audioStatus: false,
      isLoading: false,
      page: 1,
      last_page: "",

      // wss
      timeout_reconnect: null,
      timeoutOpen: null,
      timeoutPong: null,
      heartBeatInterval: null,
      websock: null,
      isClosed: false
    };
  },
  components: {
    VanPullRefresh,
    VanImage,
    loading,
    audioIcon
  },
  created() {
    this.initWebSocket();
  },
  activated() {
    this.init();
  },
  deactivated() {
    this.isClosed = true;
    this.clearMethod();
  },
  destroyed() {
    this.isClosed = true;
    this.clearMethod();
  },
  methods: {
    async onRefresh() {
      if (this.page >= this.last_page) {
        this.$toast('没有更多了');
        this.isLoading = false;
        return;
      }
      this.page += 1;
      await this.historyGet("more");
      this.$nextTick(() => {
        window.scrollTo(0, 0);
      });
    },
    clearMethod() {
      if (this.websock) {
        this.websock.close();
      }
      if (this.timeout_reconnect) {
        this.timeout_reconnect = null;
        clearInterval(this.timeout_reconnect);
      }
      if (this.timeoutOpen) {
        this.timeoutOpen = null;
        clearInterval(this.timeoutOpen);
      }
      if (this.timeoutPong) {
        this.timeoutPong = null;
        clearInterval(this.timeoutPong);
      }
      if (this.heartBeatInterval) {
        this.heartBeatInterval = null;
        clearInterval(this.heartBeatInterval);
      }
      if (this.audioChild) {
        this.audioChild.removeEventListener("ended");
        this.audioChild.removeEventListener("canplaythrough");
        this.audioChild.pause();
        this.audioChild = null;
      }
    },
    //wss start
    initWebSocket() {
      console.log(process.env.NODE_ENV);
      this.websock = new WebSocket(`wss://${process.env.NODE_ENV == "development" ? "dev15.yunzmall.com" : document.location.host}/ws`);
      this.websock.onmessage = this.websocketonmessage;
      this.websock.onopen = this.websocketonopen;
      this.websock.onerror = this.websocketonerror;
      this.websock.onclose = this.websocketclose;
    },
    websocketclose() {
      //关闭wss
      if (!this.isClosed) {
        this.reconnect();
      }
    },
    websocketonmessage(e) {
      if (e.data == "pong") return;
      let infoDetail = JSON.parse(e.data);
      if (infoDetail.message) {
        if (infoDetail.msg_type == 0) {
          this.addMessageToChatList(infoDetail.msg_id, infoDetail.message, 1, 0, infoDetail);
        } else if (infoDetail.msg_type == 1) {
          // 接收的是商品信息
          this.addMessageToChatList(null, infoDetail.message, 1, infoDetail.msg_type);
        }
      }
    },
    websocketonopen() {
      this.heartBeatStart();
    },
    heartBeatStart() {
      this.timeoutOpen && clearTimeout(this.timeoutOpen);
      this.timeoutOpen = setTimeout(() => {
        //这里发送一个心跳，后端收到后，返回一个心跳消息，
        if (this.websock.readyState == 1) {
          //如果连接正常
          this.websock.send(
            JSON.stringify({
              type: "register",
              data: { group: "ai_digital_human" }
            })
          );
          this.websock.send(
            JSON.stringify({
              type: "login",
              data: { session_id: this.readcookie("PHPSESSID"), group: "ai_digital_human" }
            })
          );
          this.keepHeartBeat();
        } else {
          //否则重连
          this.reconnect();
        }
      }, 1000);
    },
    readcookie(name) {
      var cookievalue = "";
      var search = name + "=";
      if (document.cookie.length > 0) {
        let offset = document.cookie.indexOf(search);
        if (offset != -1) {
          offset += search.length;
          let end = document.cookie.indexOf(";", offset);
          if (end == -1) end = document.cookie.length;
          cookievalue = unescape(document.cookie.substring(offset, end));
        }
      }
      return cookievalue;
    },
    keepHeartBeat() {
      this.heartBeatInterval = setInterval(() => {
        // 每隔5s发送一个心跳包消息
        this.websock.send(JSON.stringify({ type: "ping" }));
      }, 5000);
    },
    // 重连
    reconnect() {
      if (this.isClosed) {
        return;
      }
      this.websock = null;
      this.timeout_reconnect && clearTimeout(this.timeout_reconnect);
      this.timeout_reconnect = setTimeout(() => {
        //新连接
        this.initWebSocket();
      }, 5000);
    },
    websocketonerror(e) {
      if (!this.isClosed) {
        this.reconnect();
      }
    },
    //wss end
    closeLoad() {
      this.audioStatus = false;
    },
    showLoad() {
      this.audioStatus = true;
    },
    tap_Audio(e) {
      if (this.audioChild) {
        this.audioChild.pause();
        this.audioChild = null;
      }
      this.audioChild = new Audio(e);

      this.audioChild.addEventListener("canplaythrough", event => {
        this.audioChild
          .play()
          .catch(error => {
            this.$toast("播放失败，请检查权限是否开启");
          })
          .then(() => {
            console.log("播放中");
          });
      });
      this.audioChild.addEventListener("ended", e => {
        console.log("播放结束");
      });
    },
    checkoutURL(str) {
      // 要以http 开头  防止图片src开头
      let reg = /^(http:\/\/|https:\/\/)((\w|=|\?|\.|\/|&|-|#|;|%)+)/g;
      str = str.replace(reg, website => {
        return (
          "<span onclick='event.stopPropagation ? event.stopPropagation() : (event.cancelBubble = true); // 阻止事件冒泡'><a class='article-link-color' href='" +
          website +
          "' target='_blank'>" +
          website +
          "</a></span>"
        );
      });
      return str;
    },
    sendMsg() {
      if (this.sendStatus) {
        return;
      }
      if (!this.messageId) {
        this.$toast("请检查AI数字人配置");
        return;
      }
      this.sendMsgPost();
    },
    // 发送消息
    async sendMsgPost() {
      let { data, msg, result } = await $http.get("plugin.ai-digital-human.frontend.controllers.chat.send-message", { id: this.messageId, message: this.msgText }, "");
      if (result) {
        this.addMessageToChatList(data.id, this.msgText, 0, 0);
        this.msgText = "";
        this.sendStatus = true;
        // this.startRollPost(data.id);
        // this.sendStatus = false;
      } else {
        this.sendStatus = false;
        this.$toast(msg);
      }
    },
    // 添加消息到聊天列表 msg_type：接收的信息类型
    addMessageToChatList(id, content, directionType, msg_type, infoDetail) {
      if (infoDetail && infoDetail.msg_type == 0) {
        if (infoDetail.begin) {
          this.sendStatus = true;
        }
        if (infoDetail.end) {
          this.sendStatus = false;
        }
        const index = this.chatList.findIndex(item => item.id == id && item.direction_type == 1);
        if (index !== -1) {
          this.$set(this.chatList[index], "content", this.chatList[index].content + content);
          return;
        }
        this.$set(this.chatList, this.chatList.length, { id, content, direction_type: directionType, msg_type });
        return;
      }
      this.sendStatus = false;
      this.scrollToBottom();
      this.$set(this.chatList, this.chatList.length, { id, content, direction_type: directionType, msg_type });
    },
    // 滚动到底部
    scrollToBottom() {
      this.$nextTick(() => {
        window.scrollTo(0, window.document.body.scrollHeight);
      });
    },
    // 初始化
    async init() {
      this.chatList = [];
      this.page = 1;
      this.last_page = 1;
      let { data, msg, result } = await $http.get("plugin.ai-digital-human.frontend.controllers.chat.index", {}, "");
      if (result) {
        this.messageId = data.id;
        this.ai_avatar = data.ai_avatar;
        this.memberInfo = data.member_info;
        this.xf_open = data.xf_open == 1 ? true : false;
        this.historyGet();
      } else {
        this.$toast(msg);
      }
    },
    async historyGet() {
      let { data, msg, result } = await $http.get(
        "plugin.ai-digital-human.frontend.controllers.chat.chats",
        {
          page: this.page,
          chat_id: this.messageId
        },
        "."
      );
      if (result) {
        let array = data.list.data;
        for (let i = 0; i < array.length; i++) {
          this.loadSetList(array[i].id, array[i].content, array[i].member_id ? 0 : 1, array[i].msg_type);
        }
        this.last_page = data.list.last_page;
        this.isLoading = false;
      } else {
        this.$toast(msg);
      }
    },
    loadSetList(id, content, directionType, msg_type, infoDetail) {
      this.chatList.unshift({ id, content, direction_type: directionType, msg_type, infoDetail });
    }
  }
};
</script>
<style lang="scss" scoped>
.chatWindowAi {
  padding: 0 0.9rem;
  position: relative;
  height: 100vh;

  .no-connect {
    position: fixed;
    top: 40px;
    left: 0;
    width: 100%;
    color: #f56c6c;
    background: #fef0f0;
    border-color: #fbc4c4;
    padding: 10px;
    z-index: 10;
  }

  .chat-scroll {
    padding-top: 0.5rem;
    padding-bottom: 3rem;
    transition: 0.3s;
  }

  .conversation {
    margin-bottom: 1.2rem;
    position: relative;

    .history {
      padding-bottom: 20px;

      .title {
        font-size: 14px;
        color: #265bed;
        text-align: center;
      }
    }

    .system-opt-message {
      width: 100%;
      text-align: center;
      font-size: 12px;
      color: #666;
      height: 1.5rem;
      line-height: 1.5rem;
    }
  }

  .chat-msg {
    width: 100%;

    .avater {
      width: 2.281rem;
      height: 2.281rem;
      text-align: center;
      box-sizing: border-box;
      position: absolute;

      img {
        width: 100%;
        height: 100%;
        border-radius: 50%;
      }
    }

    .content {
      position: relative;

      .name {
        font-size: 12px;
        color: #666;
        line-height: 1;
        margin-bottom: 0.3rem;
      }

      .txt {
        max-width: 16rem;
        word-wrap: break-word;
        word-break: break-all;
        text-align: justify;
        padding: 0.6rem;
        border-radius: 0.3rem;
        position: relative;
      }

      a {
        color: #366092;
      }

      .arrow-l {
        position: absolute;
        width: 0;
        height: 0;
        left: -7px;
        border-color: #fff transparent transparent transparent;
        border-style: solid;
        border-width: 10px 0 0 10px;
        top: 8px;
      }

      .arrow-r {
        position: absolute;
        width: 0;
        height: 0;
        right: -7px;
        border-color: transparent transparent transparent #f14e4e;
        border-style: solid;
        border-width: 0 0 10px 10px;
        top: 8px;
      }
    }

    &::after {
      content: "";
      display: table;
      clear: both;
    }
  }

  .my-msg {
    text-align: right;
    padding-left: 1rem;
    box-sizing: border-box;

    .avater {
      right: 0;
      top: 0;
    }

    .content {
      padding-right: 3rem;
      float: right;
      text-align: right;

      .my-info {
        position: relative;
        display: inline-block;

        .txt {
          display: inline-flex;
          font-size: 0.875rem;
          color: #fff;
          background: #f14e4e;
        }

        a {
          color: #366092;
        }
      }

      .name {
        font-size: 12px;
        color: #666;
        line-height: 1;
        margin-bottom: 0.3rem;
      }
    }
  }

  .other-msg {
    vertical-align: top;
    width: 100%;
    box-sizing: border-box;
    position: relative;
    padding-right: 1rem;

    .content {
      padding-left: 3rem;
      float: left;
      text-align: left;

      .other-info {
        position: relative;
        display: inline-block;

        .txt {
          font-size: 0.875rem;
          color: #333;
          background: #fff;
        }

        a {
          color: #366092;
        }
      }

      .content-time {
        margin-left: 0.6rem;
      }
    }

    .avater {
      left: 0;
      top: 0;
    }
  }

  .chat-content-opt {
    width: 5rem;

    .chat-content-opt-item {
      width: 100%;
      text-align: center;
      line-height: 2;
      border-bottom: 1px solid #f5f5f5;
    }
  }

  .chat-footer {
    position: fixed;
    left: 0;
    right: 0;
    bottom: 0;
    border-top: 1px solid #ddd;
    height: 3rem;
    transition: 0.3s;

    .show_tool_bar {
      position: absolute;
      top: -2.75rem;
      left: 0;
      right: 0;
      height: 2.75rem;
      background-color: #e3e3e3;

      .chat_tool_bars {
        display: flex;
        align-items: center;
        flex-wrap: nowrap;
        height: 2.75rem;
        padding: 0 0.906rem;
        overflow-x: auto;

        .chat_tool_item {
          flex-shrink: 0;
          display: flex;
          align-items: center;
          height: 1.625rem;
          padding: 0 0.6rem;
          margin-right: 1.063rem;
          font-size: 0.688rem;
          color: #7c7c7c;
          background-color: #fff;
          border-radius: 0.813rem;
          border: solid 0.031rem #a9a9a9;

          &:last-child {
            margin-right: 0;
          }
        }
      }
    }

    .chat-opt-input {
      display: flex;
      align-items: center;
      width: 100%;
      height: 3rem;
      background-color: #e3e3e3;

      .chat-opt-input-box {
        position: relative;
        display: flex;

        &::after {
          content: "";
          clear: both;
          display: table;
        }

        .chat-opt-input-more-icon {
          margin-left: 0.563rem;
          margin-top: 0.3rem;
          display: block;
        }

        .inputWrapper {
          display: flex;
          align-items: center;
          width: 15.469rem;
          height: 2rem;
          padding: 0 0.4rem;
          margin-left: 0.813rem;
          border-radius: 1rem;
          background-color: #fff;

          .edit-ipt {
            flex: 1;
            padding: 0 0.2rem;
            border-width: 1px;
            border-style: none;
            border-color: #666;
            width: calc(100% - 30px); // 手机屏幕小时，表情挡住发送按钮
          }

          //.chat-opt-input-emoji-icon{
          //
          //}
        }

        .chat-opt-send-msg-btn {
          display: flex;
          align-items: center;
          justify-content: center;
          width: 3.656rem;
          height: 2rem;
          margin-left: 0.5rem;
          font-size: 0.862rem;
          color: #fff;
          background-color: #f14e4e;
          border-radius: 1rem;
        }

        .disabled-send {
          background-color: #ccc;
        }
      }
    }

    &.pcStyle {
      width: 375px;
      left: 50%;
      transform: translateX(-50%);
    }
  }

  .faces_content {
    width: 100%;
    padding: 10px 5px;
    height: 195px;
    overflow-y: scroll;
  }

  .face-item {
    text-align: center;
    display: inline-block;
    height: 36px;
    width: 36px;

    img {
      width: 25px;
      height: 25px;
    }
  }

  .more-opt-con {
    padding: 1rem;

    &::after {
      clear: both;
      content: "";
      display: table;
    }

    .more-opt-item {
      width: 4rem;
      text-align: center;
      float: left;
    }

    //.more-opt-item-icon{
    //
    //}
  }

  .goods-con {
    background: #fff;
    display: flex;
    padding: 0.8rem;
    min-width: 15rem;

    .goods-img {
      width: 4.5rem;

      img {
        width: 4rem;
        height: 4rem;
      }
    }

    .goods-txt {
      flex: 1;

      .goods-title {
        font-size: 14px;
      }

      .goods-price {
        margin-top: 0.8rem;
        color: #fb4a4a;
      }
    }
  }

  .search-list-popup-con {
    .search-con {
      width: 90%;
      position: relative;
      padding-top: 1rem;
      margin: auto;
    }

    input {
      border: none;
      width: 100%;
      height: 2rem;
      background: #f5f5f5;
      border-radius: 0.3rem;
      padding: 0.3rem 0.5rem;
    }

    i {
      font-size: 1.65rem;
      color: #999;
      margin-right: 0.375rem;
      position: absolute;
      right: 0;
    }

    .goods-con {
      width: 100%;
      border-bottom: 1px solid #f5f5f5;

      .goods-txt {
        text-align: left;
        padding-left: 0.5rem;
      }

      .goods-send {
        width: 4rem;
        padding-left: 0.5rem;
      }

      .goods-send-btn {
        display: inline-block;
        color: #fff;
        width: 100%;
        text-align: center;
        background: #fb4a4a;
        border-radius: 0.3rem;
        padding: 0.3rem 0;
        margin-top: 40%;
      }
    }

    .order-con {
      .order-item-con {
        border-bottom: none;
      }

      .order-footer {
        display: flex;
        justify-content: space-between;
        border-bottom: 1px solid #f5f5f5;
        padding-bottom: 0.5rem;
      }

      .send-btn {
        display: inline-block;
        color: #fff;
        text-align: center;
        background: #fb4a4a;
        border-radius: 0.3rem;
        padding: 0.15rem 0.6rem;
      }
    }

    .reply-con {
      width: 100%;
      border-bottom: 1px solid #f5f5f5;
      display: flex;
      padding: 0.8rem;

      .reply-txt {
        text-align: left;
        padding-left: 0.5rem;
        flex: 1;
      }

      .reply-title {
        font-size: 16px;
      }

      .reply-content {
        font-size: 12px;
        color: #333;
      }

      .reply-send {
        width: 4rem;
        padding-left: 0.5rem;
      }

      .reply-send-btn {
        display: inline-block;
        color: #fff;
        width: 100%;
        text-align: center;
        background: #fb4a4a;
        border-radius: 0.3rem;
        padding: 0.3rem 0;
        margin-top: 10%;
      }
    }

    .transfer-con {
      width: 100%;
      border-bottom: 1px solid #f5f5f5;
      display: flex;
      padding: 0.8rem;

      .transfer-avatar {
        width: 4.5rem;

        img {
          width: 4rem;
          height: 4rem;
        }
      }

      .transfer-txt {
        text-align: left;
        padding-left: 0.5rem;
        flex: 1;
      }

      .transfer-title {
        font-size: 16px;
      }

      .transfer-content {
        font-size: 12px;
        color: #333;
      }

      .transfer-send {
        width: 4rem;
        padding-left: 0.5rem;
      }

      .transfer-send-btn {
        display: inline-block;
        color: #fff;
        width: 100%;
        text-align: center;
        background: #fb4a4a;
        border-radius: 0.3rem;
        padding: 0.3rem 0;
        margin-top: 10%;
      }
    }
  }
  .send-msg-loading {
    position: absolute;
    left: -2rem;

    img {
      width: 2rem;
      height: 2rem;
    }
  }
}
</style>
